/*
 * Copyright (C) 2006 Roman Krashanitsa
 *
 * @author Roman Krashanitsa
 *
 * This file is part of paparazzi.
 *
 * paparazzi is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * paparazzi is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with paparazzi; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA. 
 *
 */



/*
 * Main class for communication. Links hardware interface classes 
 * to the protocol classes. 
 */
package pprz;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Frame;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

import javax.comm.UnsupportedCommOperationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.helpers.DefaultHandler;

import pprz.components.LogPlayerDevicePanel;
import pprz.data_components.Aircraft;
import pprz.data_components.Dev2Proto;
import pprz.data_components.LogPlayerDevice;
import pprz.data_components.LogPlayerDeviceProtocol;
import pprz.data_components.LogPlayerMsgProtocol;
import pprz.data_components.MsgProtocol;
import pprz.data_components.XBee;
import pprz.data_components.XBeeProtocol;
import pprz.data_components.events.DownlinkMessageEventListener;
import pprz.data_components.parsers.ConfParser;
import pprz.data_components.parsers.MessageParser;
import pprz.data_components.parsers.MessageParser.MessageFormat;
import fr.dgac.ivy.Ivy;
import fr.dgac.ivy.IvyClient;
import fr.dgac.ivy.IvyException;
import fr.dgac.ivy.IvyMessageListener;

public class Link implements IvyMessageListener, Runnable {

	// Class for registering component listeners when initialization is done.
	// All listeners calls are waiting in line
	private class Worker extends Thread {
		Link owner;
		DownlinkMessageEventListener l;
		public Worker(Link owner, DownlinkMessageEventListener l) {
			this.owner=owner;
			this.l=l;
		}
		public void run(){
			while (!owner.init_done)
			{
				try {
					sleep(10);
//					System.out.println("Alive #"+l.toString()+" !");
				} catch (InterruptedException e) {}
			}
//			System.out.println("Done #"+l.toString()+" !");
/*			if (sim_msg) 
			{
				owner.decoder.addDownlinkMessageEventListener(l);
			}
			else 
*/			{ // add all message decoders to the listener 
/*				for (Dev2Proto d : owner.downlink) {
					int tt=0;
					d._dec.addDownlinkMessageEventListener(l);
				}*/
	for (Iterator<Dev2Proto> iter = owner.downlink.iterator(); iter.hasNext(); ) {
		iter.next()._dec.addDownlinkMessageEventListener(l);
	}
			}					
		}
	}
	
	public static final boolean sim_msg = false;

	private Ivy bus;

//	private DefaultHandler parser;

	//private XBee xbee;

	//private XBeeProtocol xbeeprot;

//	private MsgProtocol decoder;

	private HashMap<Integer, Aircraft> aircrafts;

	private HashMap<Long, MessageFormat> messageFormat;

	private LinkedList<Dev2Proto> downlink;
	
	public boolean init_done;

	static final public int myAddress = 0x100;

	Link() {
		init_done=false;
		aircrafts=new HashMap<Integer, Aircraft>();
		messageFormat=new HashMap<Long, MessageFormat>();
		// create and initialize protocol objects
		
/*		if (sim_msg) 
		{
			decoder=new SimPprzMsgProtocol();
		}
		else 
*/		{
			//Make a device<-->protocol<-->decoder list
			downlink=new LinkedList<Dev2Proto>();
		}
		
		//make a thread for initialization taking long time
		Thread t=new Thread(this);
		t.start();
	}
	
	public void run()
	{
		try {
			Init();
		} catch (IvyException e) {
			
		}
	}
	
	
	//Initialize all structures
	public void Init() throws IvyException {
		// initialization, name and ready message
		bus = new Ivy("Link","Link ready",null);
		// classical subscription
		bus.bindMsg("^Hello(.*)",this);
		// inner class subscription ( think awt )
		bus.bindMsg("^Bye$",new IvyMessageListener() {
			public void receive(IvyClient client, String[] args) {
				// leaves the bus, and as it is the only thread, quits
				bus.stop();
			}
		});
		
		SAXParser sax;
    	DefaultHandler handler;
		handler = new ConfParser(aircrafts); // will make aircraft hash map
		try {
			SAXParserFactory prt=SAXParserFactory.newInstance();
			sax=prt.newSAXParser();
			sax.parse("E:\\work_comp\\Roman\\Development\\paparazzi\\paparazzi\\paparazzi3\\conf\\conf.xml", handler);
		} catch (org.xml.sax.SAXException se) {
			System.out.println("can't create conf parser");
		} catch (ParserConfigurationException se) {
			System.out.println("can't create conf parser");
		} catch (IOException ex) {
			System.out.println("IO problem reading conf.xml");
		}
		
//		aircrafts=((ConfParser)handler).getAircraftConfs();
		DefaultHandler parser = new MessageParser(messageFormat);
		try {
			SAXParserFactory prt=SAXParserFactory.newInstance();
			sax=prt.newSAXParser();
			sax.parse("E:\\work_comp\\Roman\\Development\\paparazzi\\paparazzi\\paparazzi3\\conf\\messages.xml", parser);
		} catch (org.xml.sax.SAXException se) {
			System.out.println("can't create message parser");
		} catch (ParserConfigurationException se) {
			System.out.println("can't create message parser");
		} catch (IOException ex) {
			System.out.println("IO problem");
		}		
//		messageFormat=((MessageParser)parser).messageFormat();
		
		System.out.println(((MessageParser)parser).messageFormat().values());
		System.out.println(((MessageParser)parser).noClass);
		System.out.println(((MessageParser)parser).noName);
		System.out.println(((MessageParser)parser).noId);
		System.out.println(((MessageParser)parser).noNameField);
		System.out.println(((MessageParser)parser).noUnitField);
		System.out.println(((MessageParser)parser).noTypeField);
		
		// create and initialize protocol objects
/*		if (sim_msg) 
		{
			GeographicConverter.UTM p=GeographicConverter.LLtoUTM(23, 32.23298, -110.9324);
			((SimPprzMsgProtocol)decoder).init(aircrafts,((MessageParser)parser).messageFormat(), 32.23298, -110.9324);
		}
		else 
*/		{
			//Make a device<-->protocol<-->decoder list
/*			Dev2Proto dl=new Dev2Proto(
						new XBee("COM1",myAddress,"Ground Station"),
						new DevProtocol(),
						new PprzMsgProtocol(this)				
					);
*/			
	
			LogPlayerDevicePanel dp=new LogPlayerDevicePanel();
			LogPlayerDevice dev=new LogPlayerDevice();
			dev.addPropertyChangeListener(dp);
			dev.setPortName("E:\\work_comp\\Roman\\Development\\paparazzi\\paparazzi\\paparazzi3\\var\\logs\\07_12_20__11_21_27.data");
			Dev2Proto dl=new Dev2Proto(
					dev,
					new LogPlayerDeviceProtocol(),
					new LogPlayerMsgProtocol(this)
			);
			
			Frame frame=new Frame();
			frame.setTitle(dev.getClass().getSimpleName());
			frame.setLayout(new BorderLayout());
			frame.add(dp);
			frame.setBackground(Color.black);
	         //Display the window.
			frame.setSize(frame.getLayout().preferredLayoutSize(frame));
	         //frame.setBounds(100, 100, 800, 600);
	         frame.doLayout();
	         frame.pack();
	         frame.setVisible(true);

		if (downlink!=null) downlink.add(dl);
			
		}
		bus.start(null); // starts the bus on the default domain
		init_done=true;
	}

	// callback associated to the "Hello" messages"
	public void receive(IvyClient client, String[] args) {
		try {
			bus.sendMsg("Bonjour" + ((args.length > 0) ? args[0] : ""));
		} catch (IvyException ie) {
			System.out.println("can't send my message on the bus");
		}
	}

	public void initDevices() throws UnsupportedCommOperationException, IOException
	{
		//initialize physical devices			
		if (downlink==null) return;
		for (Dev2Proto d : downlink)
		{
			d._dev.init();
			if (!(d._dev.ok)) {
				System.out.println("Device "+d._dev+" is not responding.. exiting.");
				System.exit(0);
			}
			if (d._devprot.getClass()==XBeeProtocol.class &&
				d._dev.getClass()==XBee.class)
			{
				((XBee)d._dev).enableAPI();
			}
				
		}
		//aircrafts.get(39).setUplink(downlink.get(0)); //change!!
	}
	
	
	public HashMap<Integer, Aircraft> getAircraftList() {
		return aircrafts;
	}

	public HashMap<Long, MessageFormat> getMessageFormats() {
		return messageFormat;
	}

	public LinkedList<Dev2Proto> getDevProtoList()
	{
		return downlink;
	}
	public void addDownlinkMessageEventListener(DownlinkMessageEventListener l) {
		Worker t=new Worker(this,l);
		t.start();
	}
}
